﻿'
' Will Strohl (wills@strohlsitedesign.com)
' http://www.willstrohl.com
'
'Copyright (c) 2009, Will Strohl
'All rights reserved.
'
'Redistribution and use in source and binary forms, with or without modification, are 
'permitted provided that the following conditions are met:
'
'Redistributions of source code must retain the above copyright notice, this list of 
'conditions and the following disclaimer.
'
'Redistributions in binary form must reproduce the above copyright notice, this list 
'of conditions and the following disclaimer in the documentation and/or other 
'materials provided with the distribution.
'
'Neither the name of StrohlSiteDesign.com nor the names of its contributors may be 
'used to endorse or promote products derived from this software without specific prior 
'written permission.
'
'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
'EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
'OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
'SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
'INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
'TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
'BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
'CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
'ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
'DAMAGE.
'

Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Web
Imports System.Web.Services
Imports WillStrohl.Modules.FeedHandler.FeedHandlerController

Namespace WillStrohl.Modules.FeedHandler

    ''' <summary>
    ''' Feed - this is the class used for the Feed handler, which wraps XML feeds
    ''' </summary>
    ''' <remarks></remarks>
    ''' <history>
    ''' </history>
    Public Class Feed
        Implements System.Web.IHttpHandler, System.Web.SessionState.IRequiresSessionState

#Region " Private Members "

        Private p_ModuleId As Integer = Null.NullInteger
        Private p_FeedId As Integer = Null.NullInteger
        Private p_ItemCount As Integer = Null.NullInteger
        Private p_XmlFeed As String = String.Empty
        Private p_Feed As FeedInfo = Nothing
        Private p_FeedRules As FeedRuleInfoCollection = Nothing

#End Region

#Region " Private Properties "

        ''' <summary>
        ''' Context - this property is a pointer to the HttpContext
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private ReadOnly Property Context() As HttpContext
            Get
                Return HttpContext.Current
            End Get
        End Property

        ''' <summary>
        ''' ModuleId - this property holds the ID of the RSS feed from a module, from the querystring
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private ReadOnly Property ModuleId() As Integer
            Get
                If Me.p_ModuleId <> Null.NullInteger Then
                    Return Me.p_ModuleId
                Else
                    Dim obj As Object = Me.Context.Request.Params(PARAM_MODULE_ID)
                    If Not obj Is Nothing Then
                        Me.p_ModuleId = Integer.Parse(obj.ToString, Globalization.NumberStyles.Integer)
                    End If
                End If

                Return Me.p_ModuleId
            End Get
        End Property

        ''' <summary>
        ''' FeedId - this property holds the ID of the Feed object from the querystring
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private ReadOnly Property FeedId() As Integer
            Get
                If Me.p_FeedId <> Null.NullInteger Then
                    Return Me.p_FeedId
                Else
                    Dim obj As Object = Me.Context.Request.Params(PARAM_FEED_ID)
                    If Not obj Is Nothing Then
                        Me.p_FeedId = Integer.Parse(obj.ToString, Globalization.NumberStyles.Integer)
                    End If
                End If

                Return Me.p_FeedId
            End Get
        End Property

        ''' <summary>
        ''' ItemCount - this is the number of items to show in the RSS feed from the querystring
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private ReadOnly Property ItemCount() As Integer
            Get
                If Me.p_ItemCount <> Null.NullInteger Then
                    Return Me.p_ItemCount
                Else
                    Dim obj As Object = Me.Context.Request.Params(PARAM_ITEM_COUNT)
                    If Not obj Is Nothing Then
                        Me.p_ItemCount = Integer.Parse(obj.ToString, Globalization.NumberStyles.Integer)
                    End If
                End If

                If Not Me.p_ItemCount > 0 Then
                    Me.p_ItemCount = 10
                End If

                Return Me.p_ItemCount
            End Get
        End Property

        ''' <summary>
        ''' XmlFeed - this property holds the imported XML feed string object
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private Property XmlFeed() As String
            Get
                Return Me.p_XmlFeed
            End Get
            Set(ByVal value As String)
                Me.p_XmlFeed = value
            End Set
        End Property

        ''' <summary>
        ''' Feed - this is the FeedInfo object used in the module workflow
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private ReadOnly Property Feed() As FeedInfo
            Get
                If Me.p_Feed Is Nothing Then
                    Me.p_Feed = New FeedInfo
                    Me.p_Feed = FeedHandlerController.GetFeed(Me.FeedId)
                End If

                Return Me.p_Feed
            End Get
        End Property

        ''' <summary>
        ''' FeedRules - this is the FeedRulesInfo object used in the module workflow
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private ReadOnly Property FeedRules() As FeedRuleInfoCollection
            Get
                If Me.p_FeedRules Is Nothing Then
                    Me.p_FeedRules = New FeedRuleInfoCollection
                    Me.p_FeedRules = FeedHandlerController.GetFeedRules(Me.FeedId)
                End If

                Return Me.p_FeedRules
            End Get
        End Property

#End Region

        ''' <summary>
        ''' ProcessRequest - this is the equivalent of the Page_Load method
        ''' </summary>
        ''' <param name="context"></param>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

            '
            ' We should expect a URL such as:
            ' ~/DesktopModules/WillStrohl.FeedHandler/Feed.ashx?mid={0}&amp;fid={1}&amp;ic={2}
            '
            ' mid = Module Id
            ' fid = Feed Id
            ' ic = Item Count
            '
            ' http://localhost/dnn462/DesktopModules/WillStrohl.FeedHandler/Feed.ashx?fid=1&mid=376&ic=10
            '

            context.Response.ContentType = CONTENT_TYPE_XML

            '
            ' Validate the URL parameters
            '
            If Not (Me.ModuleId > 0 Or Me.FeedId > 0) Then
                Me.XmlFeed = Me.ErrorOutput("There were missing parameters in your request.")
            End If

            If Me.Feed Is Nothing Then
                Me.XmlFeed = Me.ErrorOutput("Your xml feed id is invalid.")
            End If

            ' load up the local object
            Me.BindData()

            If String.IsNullOrEmpty(Me.XmlFeed) Then
                Me.XmlFeed = Me.ErrorOutput("There was not a xml feed found associated with your request.")
            End If

            Me.Context.Response.Write(Me.XmlFeed)
        End Sub

#Region " Private Methods "

        ''' <summary>
        ''' BindData - this method initiates the binding of all objects in the handler
        ''' </summary>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private Sub BindData()
            If Not Me.Feed Is Nothing Then
                If Not String.IsNullOrEmpty(Me.Feed.FeedUrl) Then
                    Me.ImportXmlFeed()
                    Me.ApplyXmlFeedRules()
                End If
            End If
        End Sub

        ''' <summary>
        ''' ApplyXmlFeedRules - this method iterates through and applys the replacement rules to the feed
        ''' </summary>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private Sub ApplyXmlFeedRules()
            If Not Me.FeedRules Is Nothing Then
                If Me.FeedRules.Count > 0 Then
                    Me.XmlFeed = FeedHandlerController.ApplyFeedRules(Me.XmlFeed, Me.FeedRules)
                End If
            End If
        End Sub

        ''' <summary>
        ''' ErrorOutput - in the event of an error, this method outputs additional information about the error
        ''' </summary>
        ''' <param name="ErrorText"></param>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private Overloads Function ErrorOutput(ByVal ErrorText As String) As String
            Return Me.ErrorOutput(ErrorText, Nothing)
        End Function

        ''' <summary>
        ''' ErrorOutput - in the event of an error, this method outputs additional information about the error
        ''' </summary>
        ''' <param name="ErrorText"></param>
        ''' <param name="err"></param>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Private Overloads Function ErrorOutput(ByVal ErrorText As String, ByVal err As Exception) As String
            Dim sb As New StringBuilder(20)
            sb.Append(XML_HEADER)
            sb.AppendFormat(XML_OPEN, "error")
            sb.AppendFormat(XML_ELEMENT, "errorText", ErrorText)
            If Not err Is Nothing Then
                sb.AppendFormat(XML_OPEN, "exception")
                sb.AppendFormat(XML_ELEMENT, "message", err.Message)
                sb.AppendFormat(XML_ELEMENT, "stackTrace", err.StackTrace)
                sb.AppendFormat(XML_CLOSE, "exception")
            End If
            sb.AppendFormat(XML_CLOSE, "error")
            Return sb.ToString
        End Function

        ''' <summary>
        ''' ImportXmlFeed - this method imports the XML feed to be parsed
        ''' </summary>
        ''' <remarks></remarks>
        ''' <history>
        ''' [wstrohl] - 20090324 - Added logic to grab the feed by an import url
        ''' </history>
        Private Sub ImportXmlFeed()
            Try
                If String.IsNullOrEmpty(Me.Feed.FeedImportUrl) Then
                    Me.XmlFeed = FeedHandlerController.ImportXmlFeed(Me.ModuleId)
                Else
                    Me.XmlFeed = FeedHandlerController.ImportXmlFeed(Me.Feed.FeedImportUrl)
                End If
            Catch webEx As WebException
                DotNetNuke.Services.Exceptions.LogException(webEx)
                If webEx.Status = WebExceptionStatus.Timeout Then
                    Me.XmlFeed = Me.ErrorOutput("The requested xml feed has timed out.", webEx)
                End If
            Catch ex As Exception
                DotNetNuke.Services.Exceptions.LogException(ex)
                Me.XmlFeed = Me.ErrorOutput("An unknown error has occurred while trying to load the xml feed.", ex)
            End Try
        End Sub

#End Region

        ''' <summary>
        ''' IsReusable - this method is required by the ASP.Net handler
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
            Get
                Return False
            End Get
        End Property

    End Class

End Namespace